#include <stddef.h>
#include <tuple>
#include <mutex>
#include <iomanip>
#include <iostream>
#include <unordered_map>
#include "cpptrace/cpptrace.hpp"

class AllocationRecorder {
public:
    static AllocationRecorder& GetInstance() {
        static AllocationRecorder allocation_recoder;
        return allocation_recoder;
    }

    void InsertAlloctionInfo(size_t ptr, size_t size) {
        auto bt = cpptrace::generate_trace(6);
        record_mu_.lock();
        record_table_.insert({ptr, std::make_tuple(size, bt)});
        record_mu_.unlock();
    }
    void RemoveAlloctionInfo(size_t ptr) {
        record_mu_.lock();
        record_table_.erase(ptr);
        record_mu_.unlock();
    }
    ~AllocationRecorder() {
        for (const auto& record_info : record_table_) {
            std::cerr << "memory leak at: 0x" << std::hex << record_info.first << " with size:" 
                << std::dec << std::get<0>(record_info.second) << std::endl;
            auto bt = std::get<1>(record_info.second);
            bt.print();
        }
    }
    std::unordered_map<size_t, std::tuple<size_t, cpptrace::stacktrace>> record_table_;
    std::mutex record_mu_;
};
extern "C" {
void insert_alloction_info(size_t ptr, size_t size) {
    AllocationRecorder::GetInstance().InsertAlloctionInfo(ptr, size);
}

void remove_alloction_info(size_t ptr) {
    AllocationRecorder::GetInstance().RemoveAlloctionInfo(ptr);
}
}